<template>
  <div class="chartsContent">
    <div class="chart_type">
      <div class="type_left">
        <!-- <p class="">Time</p> -->
        <p @click="changeTime(item.type)" v-for="(item, index) in minuteList" :key="index"
          :class="time == item.type ? 'active' : ''">
          {{ item.name }}
        </p>
      </div>
      <i class="iconfont icon-zhexiantu-xianxing"></i>
    </div>
    <div ref="chartDom" class="chart_line" style="width: 100%; height: 86%" v-loading="loading"
      element-loading-background="#202b2c" element-loading-svg-view-box="-10, -10, 50, 50" :element-loading-spinner="svg">
    </div>
    <div class="bottom_type">
      <div class="type_left">
        <p>MA</p>
        <p>EMA</p>
        <p>BOLL</p>
        <p>SAR</p>
      </div>
      <div class="type_left">
        <p v-for="(item, index) in indicators" :key="index" :style="item.select ? 'color:#f5bd08' : ''"
          @click="toggleIndicator(item.name, index)">
          {{ item.name }}
        </p>
      </div>
    </div>
  </div>
</template>
  
<script setup>
import { init, dispose } from "klinecharts";
import { ref, onMounted, onUnmounted, computed, nextTick, watch, onBeforeUnmount } from "vue";
import { klineHistory } from "../api/stock.js"
const indicators = ref([
  {
    name: "VOL",
    select: false,
  },
  {
    name: "MACD",
    select: false,
  },
  {
    name: "RSI",
    select: false,
  },
  {
    name: "KDJ",
    select: false,
  },
  {
    name: "OBV",
    select: false,
  },
  {
    name: "WR",
    select: false,
  },
]);
// const minuteList = ["5m", "15m", "30m", "1D", "1W", "1M"];
const minuteList = ref([
  {
    name: "Time",
    type: "1min"
  },
  {
    name: "5m",
    type: "5min"
  },
  {
    name: "15m",
    type: "15min"
  },
  {
    name: "30m",
    type: "30min"
  },
  {
    name: "1D",
    type: "1hour"
  },
  {
    name: "1D",
    type: "daily"
  },
  {
    name: "1W",
    type: "weekly"
  },
  {
    name: "1M",
    type: "monthly"
  },
])
const symbolName = ref('')
// const indicatorsIndex = ref(0);
const indicatorsMap = new Map();
const chartDom = ref(null);
const chartInstance = ref(null);
const loading = ref(true)
const time = ref("1min")

const emit = defineEmits(['message']); // 发送至父组件消息
const svg = `
        <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
      `;
const props = defineProps({
  klineName: String,
})



onMounted(() => {
  // initChart();
  // setTimeout(() => {
  //   emit('message', 155);
  // }, 0);
  setupResizeObserver();

})
const changeTime = (type) => {
  time.value = type
  console.log("数据----", props.klineName)
  getKline(props.klineName)
}
const getKline = async (klineName) => {
  const retryDelay = 2000; // 2 秒

  const doRequest = async () => {
    if (ws) {
      close()
    }

    loading.value = true
    console.log("klinecharts-----", klineName)
    const data = {
      symbol: klineName,
      freq: time.value
    }

    try {
      const res = await klineHistory(data)
      if (res.code == 200) {
        loading.value = false
        res.data.forEach((item) => {
          item.timestamp = new Date(item.date).getTime()
        })
        symbolName.value = klineName
        initChart(res.data)
        connect()
        // 成功就不会再重试
      } else {
        console.error("请求失败，2 秒后重试")
        setTimeout(doRequest, retryDelay)
      }
    } catch (error) {
      console.error("请求异常，2 秒后重试", error)
      setTimeout(doRequest, retryDelay)
    }
  }

  doRequest()
}
// 设置尺寸监听
const setupResizeObserver = () => {
  window.addEventListener("resize", () => {
    chartInstance.value.resize();
  });
};

//测试动态添加

// 用来存储当前生成的测试数据
let lastWsData = {}

const initChart = (data) => {
  if (chartInstance.value) {
    dispose(chartInstance.value); // 销毁旧实例
    console.log('销毁');
    // chartInstance.value.applyNewData(data)
  }
  if (chartDom.value) {
    // 正确初始化图表实例
    chartInstance.value = init(chartDom.value, {
      styles: {
        // 去除主K线图与指标区域之间的分割线
        separator: {
          color: "transparent", // 设置为透明
          size: 0, // 设置大小为0
        },
        // 去除指标区域之间的分割线
        indicator: {
          separator: {
            color: "transparent",
            size: 0,
          },
        },
        grid: {
          horizontal: {
            color: "#2a2e39",
            size: 1,
          },
          vertical: {
            color: "#2a2e39",
            size: 1,
          },
        },
        candle: {
          type: "area",
          area: {
            lineColor: "#3D7AEB",
            lineSize: 2,
            fillColor: "rgba(61, 122, 235, 0.2)",
          },
          priceMark: {
            high: { show: true },
            low: { show: true },
            last: { show: true },
          },
        },
        xAxis: {
          axisLine: {
            color: "#2a2e39",
          },
          tickLine: {
            color: "#2a2e39",
          },
          tickText: {
            color: "#7F7F7F",
          },
        },
        yAxis: {
          axisLine: {
            color: "#2a2e39",
          },
          tickLine: {
            color: "#2a2e39",
          },
          tickText: {
            color: "#7F7F7F",
          },
        },
      },
    });
    // const data = generateSampleData();
    chartInstance.value.applyNewData(data);
    lastWsData = data[data.length - 1]
    console.log(lastWsData, '最后一条');
  }
};


const toggleIndicator = (indicator, index) => {
  // 检查指标是否已存在
  if (indicatorsMap.has(indicator)) {
    // 如果存在，移除该指标
    chartInstance.value.removeIndicator({ name: indicator });
    // 删除数组中指标的数据
    indicatorsMap.delete(indicator);
    // 样式去除
    indicators.value[index].select = false;
    return;
  } else {
    indicators.value[index].select = true;
  }

  // 定义指标高度配置
  const indicatorConfigs = {
    VOL: { heightRatio: 0.05, series: "volume" },
    MACD: { heightRatio: 0.15, series: "normal" },
    RSI: { heightRatio: 0.15, series: "normal" },
    KDJ: { heightRatio: 0.15, series: "normal" },
    OBV: { heightRatio: 0.15, series: "normal" },
    WR: { heightRatio: 0.15, series: "normal" }, // 新增WR指标配置
  };

  // 计算主图剩余高度 (1 - 所有指标高度总和)
  let totalIndicatorHeight = 0;
  indicatorsMap.forEach(() => {
    totalIndicatorHeight += 0.15; // 每个指标占15%
  });

  const mainHeightRatio = Math.max(0.4, 1 - totalIndicatorHeight - 0.15); // 主图最小保持40%

  // 创建新指标
  const config = indicatorConfigs[indicator];
  let newIndicator;

  switch (indicator) {
    case "VOL":
      newIndicator = chartInstance.value.createIndicator({
        name: "VOL",
        calcParams: [5, 10, 20],
        series: config.series,
        visible: true,
        height: 10,
        styles: {
          bar: {
            upColor: "#ef5350",
            downColor: "#26a69a",
          },
          line: {
            colors: ["#FF9800", "#2196F3", "#9C27B0"],
          },
        },
      });
      break;

    case "MACD":
      newIndicator = chartInstance.value.createIndicator({
        name: "MACD",
        calcParams: [12, 26, 9],
        series: config.series,
        visible: true,
        heightRatio: config.heightRatio,
        styles: {
          line: {
            colors: ["#FF9800", "#2196F3"],
          },
          bar: {
            upColor: "#ef5350",
            downColor: "#26a69a",
          },
        },
      });
      break;

    case "RSI":
      newIndicator = chartInstance.value.createIndicator({
        name: "RSI",
        calcParams: [6, 12, 24],
        series: config.series,
        visible: true,
        heightRatio: config.heightRatio,
        styles: {
          line: {
            colors: ["#FF9800", "#2196F3", "#9C27B0"],
          },
        },
      });
      break;

    case "KDJ":
      newIndicator = chartInstance.value.createIndicator({
        name: "KDJ",
        calcParams: [9, 3, 3],
        series: config.series,
        visible: true,
        heightRatio: config.heightRatio,
        styles: {
          line: {
            colors: ["#FF9800", "#2196F3", "#9C27B0"],
          },
        },
      });
      break;

    case "OBV":
      newIndicator = chartInstance.value.createIndicator({
        name: "OBV",
        calcParams: [30],
        series: config.series,
        visible: true,
        heightRatio: config.heightRatio,
        styles: {
          line: {
            colors: ["#FF9800", "#2196F3"],
          },
        },
      });
      break;

    case "WR":
      newIndicator = chartInstance.value.createIndicator({
        name: "WR",
        calcParams: [14], // 通常使用14周期
        series: config.series,
        visible: true,
        heightRatio: config.heightRatio,
        styles: {
          line: {
            colors: ["#FF9800"], // 橙色线条
            size: 1,
          },
          // 添加水平参考线 (超买超卖区域)
          levels: [
            { value: 20, color: "#FF0000" }, // 超卖线
            { value: 80, color: "#00FF00" }, // 超买线
          ],
        },
      });
      break;

    default:
      console.warn(`Unknown indicator: ${indicator}`);
      return;
  }
  console.log("zhibiaoshuju 000000", indicatorsMap);
  // 将新指标存入Map
  indicatorsMap.set(indicator, newIndicator);
};


/**
 * 拼接一条新的 K 线数据
 *
 * 逻辑：
 *  - 如果新价格低于上一条最低价：最低价改为新价格，最高价用上一条的最高价，
 *    收盘价 = 上一条最高价 + 新价格 + 上一条开盘价 + 新价格
 * 
 *  - 如果新价格高于上一条最高价：最高价改为新价格，最低价用上一条的最低价，
 *    收盘价 = 上一条最低价 + 新价格 + 上一条开盘价 + 新价格
 * 
 *  - 如果新价格在上一条最高/最低之间：最高价和最低价都不变，
 *    收盘价 = 新价格
 *
 * @param {Object} lastBar - 上一条 K 线数据
 * @param {number} newPrice - 当前推送的新价格
 * @returns {Object} 新的 K 线数据对象
 */


/**
 * @param {Object} lastWsData - 上一条 K 线数据（已在外部定义，不是参数）
 * @param {number} newPrice - 当前推送的新价格
 * @returns {Object} 新的 K 线数据
 * 
 * 新数据的价格和当前你查看的股票图表里面的价格比较：
 * 
 * 如果当前价格小于最低价：
 *   最高价 = 上一条最高
 *   最低价 = 当前推送价格
 *   开盘价 = 上一条开盘
 *   收盘价 = 当前推送价格
 * 
 * 如果当前价格大于最高价：
 *   最低价 = 上一条最低
 *   最高价 = 当前推送价格
 *   开盘价 = 上一条开盘
 *   收盘价 = 当前推送价格
 * 
 * 如果当前价格在区间内：
 *   开盘价 = 上一条开盘
 *   最低价 = 上一条最低
 *   最高价 = 上一条最高
 *   收盘价 = 当前推送价格
 */
function createNewKline(date, newPrice) {
  // console.log(date, 'lastWsData', newPrice);

  // ✅ 从作用域直接使用 lastWsData
  let open = lastWsData.open;
  let high, low, close;

  if (newPrice < lastWsData.low) {
    // ✅ 情况1：低于最低价
    low = newPrice;
    high = lastWsData.high;
    close = newPrice; // ✅ 修正：直接当前推送价格
  } else if (newPrice > lastWsData.high) {
    // ✅ 情况2：高于最高价
    high = newPrice;
    low = lastWsData.low;
    close = newPrice; // ✅ 修正
  } else {
    // ✅ 情况3：区间内
    high = lastWsData.high;
    low = lastWsData.low;
    close = newPrice;
  }

  let datecopy = date; // ✅ 用传入的 date
  if (/\.\d{4,}/.test(datecopy)) {
    datecopy = datecopy.replace(/(\.\d{3})\d+/, '$1');
  }

  console.log(date, datecopy);

  return {
    open: open,                // 开盘价
    high: high,                // 最高价
    low: low,                  // 最低价
    close: close,              // 收盘价
    date: date,                // ✅ 用传入时间
    timestamp: new Date(datecopy).getTime(), // 时间戳
    ticker: lastWsData.ticker, // ✅ 作用域里的 lastWsData
    volume: 0                  // 成交量
  };
}



// WebSocket 连接地址


// WebSocket 实例变量（非响应式）
let ws = null

// 连接状态，响应式，方便模板显示
const isConnected = ref(false)

// 收到的消息列表，响应式，模板显示用
const messagesWs = ref([])

// 建立 WebSocket 连接
function connect() {
  const token = localStorage.getItem('token') || ''
  const symbols = symbolName.value || ''

  // const url = `ws://192.168.31.6:10000/ws?token=${encodeURIComponent(token)}&symbols=${encodeURIComponent(symbols)}`
  const url = `ws://43.225.159.231:7800/ws?token=920c764fb242592ef55d04fffed8784f&symbols=${encodeURIComponent(symbols)}`




  ws = new WebSocket(url)

  // 连接成功回调
  ws.onopen = () => {
    isConnected.value = true
    console.log('WebSocket 已连接')
  }

  ws.onmessage = (event) => {
    try {
      const parsedData = JSON.parse(event.data); // 把 JSON 字符串转成对象
      messagesWs.value.push(parsedData); // 存入数组
      console.log('收到消息:', parsedData.data);
      const data = createNewKline(parsedData.data[0], parsedData.data[2])
      chartInstance.value.updateData(data)

      emit('message', parsedData.data[2]);
      lastWsData = data
    } catch (error) {
      // console.error('消息解析失败:', error, event.data);
      console.log(event.data, '解析失败的数据');
    }
  };

  // 连接关闭回调，不再重连
  ws.onclose = () => {
    isConnected.value = false
    console.log('连接关闭')
  }

  // 连接错误回调，不再重连
  ws.onerror = () => {
    console.error('WebSocket 错误，关闭连接')
    ws.close()
  }
}

// 发送消息函数，调用前先判断连接状态
function send(msg) {
  if (ws && isConnected.value) {
    ws.send(msg)
  } else {
    console.warn('WebSocket 未连接，无法发送消息')
  }
}

// 主动关闭连接
function close() {
  if (ws) {
    ws.close()
  }
}

// 页面按钮调用，发送测试消息
function sendMessage() {
  send('你好，服务器')
}

onBeforeUnmount(() => {
  dispose(chartInstance.value)
  close()
})





defineExpose({
  getKline
});


</script>


  
<style scoped lang="less">
.chartsContent {
  height: calc(100% - 30px);
}

.chart_type {
  width: 100%;
  display: flex;
  align-items: center;

  .type_left {
    display: flex;
    align-items: center;
    margin-right: 15px;
    padding: 8px 0;

    p {
      cursor: pointer;
      line-height: 20px;
      color: #666;
      font-size: 14px;
      padding: 0 5px;
    }

    .active {
      color: #1fb1ea;
      font-weight: 700;
    }
  }

  .icon-zhexiantu-xianxing {
    color: #666;
    font-size: 16px;
    font-weight: 700;
  }
}

.chart_line {
  width: 100%;
  height: 443px;
}

.bottom_type {
  display: flex;
  align-items: center;
  padding: 8px 0;

  .type_left:first-child {
    width: 40%;
  }

  .type_left {
    flex: 1;
    display: flex;
    align-items: center;

    p {
      padding: 0 5px;
      line-height: 20px;
      color: #666;
      font-size: 11px;
      cursor: pointer;
    }
  }
}
</style>
  